package com.xcity.db.type;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import com.xcity.game.currency.CurrencyType;
import com.xcity.game.currency.ICurrency;
import com.xcity.game.currency.ICurrencyFactory;
import com.xcity.game.currency.factory.DefaultCurrencyFactory;
import com.xcity.game.io.DeserializeStream;
import com.xcity.game.io.SerializeStream;

public class CurrenciesTypeHandler extends BaseTypeHandler<ICurrency[]> {

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, ICurrency[] parameter, JdbcType jdbcType)
			throws SQLException {
		ps.setBytes(i, serialize(parameter));
	}

	@Override
	public ICurrency[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
		return deserialize(rs.getBytes(columnName));
	}

	@Override
	public ICurrency[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		return deserialize(rs.getBytes(columnIndex));
	}

	@Override
	public ICurrency[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		return deserialize(cs.getBytes(columnIndex));
	}
	
	private static ICurrency[] deserialize(byte[] data) {
		if (data == null || data.length == 0) {
			return null;
		}
		DeserializeStream stream = new DeserializeStream(data);
		stream.read(); // version
		int len = stream.readShort(); // length
		int capacity = CurrencyType.size();
		ICurrency[] currencies = new ICurrency[len < capacity ? capacity : len];
		int i = 0;
		ICurrencyFactory factory = DefaultCurrencyFactory.getInstance();
		for (; i < len; i++) {
			CurrencyType type = CurrencyType.forCode(i);
			currencies[i] = factory.create(type, stream);
		}
		// new currencies
		for (; i < capacity; i++) {
			CurrencyType type = CurrencyType.forCode(i);
			currencies[i] = factory.create(type, null);
		}
		return currencies;
	}
	
	private static byte[] serialize(ICurrency[] currencies) {
		if (currencies == null || currencies.length == 0) {
			return null;
		}
		SerializeStream stream = new SerializeStream(256);
		stream.write(0); // version
		stream.writeShort((short) currencies.length); // length
		for (ICurrency c : currencies) {
			if (c != null) {
				c.write(stream);
			} else {
				stream.write(0); // mark
			}
		}
		return stream.toByteArray();
	}

}
